#include <wctype.h>
#include <stdlib.h>
#include "util/pinyindata.h"

#define UNICODE_BEGIN               0x4e00
#define UNICODE_END                 0x9fa5

#define IS_CN_CHAR(wch)             ((wch) >= UNICODE_BEGIN && (wch) <= UNICODE_END)
#define GET_PY_CODE(wch)            (pinyincmp[(wch) - UNICODE_BEGIN] + UNICODE_BEGIN)
#define GET_CMP_CODE(wch)           (int)(IS_CN_CHAR(wch) ? GET_PY_CODE(wch) : (wch))

#define CMP_CHAR(wch1, wch2)        (GET_CMP_CODE(wch1) - GET_CMP_CODE(wch2))
#define CMP_CASE_CHAR(wch1, wch2)   (GET_CMP_CODE(towlower(wch1)) - GET_CMP_CODE(towlower(wch2)))

int pinyin_charcmp(unsigned short wch1, unsigned short wch2)
{
    return CMP_CHAR(wch1, wch2);
}

int pinyin_strncmp(const unsigned short *str1, const unsigned short *str2, unsigned long length)
{
    unsigned long i = 0;

    if(str1 == NULL)
    {
        return -1;
    }

    if(str2 == NULL)
    {
        return 1;
    }

    for(i = 0; i < length; i++)
    {
        if(!str1[i] || !str2[i] || str1[i] != str2[i])
        {
            break;
        }
    }

    return pinyin_charcmp(str1[i], str2[i]);
}
unsigned short utf8ToUnicode(const unsigned char *utf8)
{
    unsigned short u1 = 0;
    if (*utf8 >= 0x00 && *utf8 <= 0x7f)//说明最高位为'0'，这意味着utf8编码只有1个字节！
    {
        u1 = *utf8;
    }
    else if ((*utf8 & 0xe0)== 0xc0)//只保留最高三位，看最高三位是不是110，如果是则意味着utf8编码有2个字节！
    {
        *(unsigned char *)(&u1) = ((*utf8 & (0x1f) & (0x03)) << 6) | (*(utf8 + 1) & (0x3f));
        *((unsigned char *)(&u1) + 1) = *utf8 & (0x1f) >> 2;//留下其保留的三位
    }
    else if ((*utf8 & (0xf0))== 0xe0)//只保留最高四位，看最高三位是不是1110，如果是则意味着utf8编码有3个字节！
    {
        *(unsigned char *)(&u1) = (((*(utf8 + 1) & (0x3f)) & (0x03)) << 6) | (*(utf8 + 2) & (0x3f));
        *((unsigned char *)(&u1) + 1) = ((*utf8 & (0x1f)) << 4) | ((*(utf8 + 1) & (0x3f)) >> 2);
    }

    return u1;
}

int pinyin_strncmp_utf8(const void *str1, const void *str2)
{
    unsigned short u1 = 0;
    unsigned short u2 = 0;
    unsigned char *ps1 = (unsigned char *)str1;
    unsigned char *ps2 = (unsigned char *)str2;
    int ret = 0;

    while (*ps1 && *ps2)    // 都不为0
    {
        if (*ps1 >= 0x00 && *ps1 <= 0x7f)//说明最高位为'0'，这意味着utf8编码只有1个字节！
        {
            u1 = *ps1;
        }
        else if ((*ps1 & 0xe0)== 0xc0)//只保留最高三位，看最高三位是不是110，如果是则意味着utf8编码有2个字节！
        {
            char t1 = 0;
            char t2 = 0;

            t1 = *ps1 & (0x1f);//高位的后5位！（去除了头部的110这个标志位）
            ps1++;
            t2 = *ps1 & (0x3f);//低位的后6位！（去除了头部的10这个标志位）

            *(unsigned char *)(&u1) = t2 | ((t1 & (0x03)) << 6);
            *((unsigned char *)(&u1) + 1) = t1 >> 2;//留下其保留的三位
        }
        else if ((*ps1 & (0xf0))== 0xe0)//只保留最高四位，看最高三位是不是1110，如果是则意味着utf8编码有3个字节！
        {
            wchar_t t1 = 0;
            wchar_t t2 = 0;
            wchar_t t3 = 0;
            t1 = *ps1 & (0x1f);
            ps1++;
            t2 = *ps1 & (0x3f);
            ps1++;
            t3 = *ps1 & (0x3f);

            *(unsigned char *)(&u1) = ((t2 & (0x03)) << 6) | t3;
            *((unsigned char *)(&u1) + 1) = (t1 << 4) | (t2 >> 2);
        }

        if (*ps2 >= 0x00 && *ps2 <= 0x7f)//说明最高位为'0'，这意味着utf8编码只有1个字节！
        {
            u2 = *ps2;
        }
        else if ((*ps2 & 0xe0)== 0xc0)//只保留最高三位，看最高三位是不是110，如果是则意味着utf8编码有2个字节！
        {
            char t1 = 0;
            char t2 = 0;

            t1 = *ps2 & (0x1f);//高位的后5位！（去除了头部的110这个标志位）
            ps2++;
            t2 = *ps2 & (0x3f);//低位的后6位！（去除了头部的10这个标志位）

            *(unsigned char *)(&u2) = t2 | ((t1 & (0x03)) << 6);
            *((unsigned char *)(&u2) + 1) = t1 >> 2;//留下其保留的三位
        }
        else if ((*ps2 & (0xf0))== 0xe0)//只保留最高四位，看最高三位是不是1110，如果是则意味着utf8编码有3个字节！
        {
            wchar_t t1 = 0;
            wchar_t t2 = 0;
            wchar_t t3 = 0;
            t1 = *ps2 & (0x1f);
            ps2++;
            t2 = *ps2 & (0x3f);
            ps2++;
            t3 = *ps2 & (0x3f);

            *(unsigned char *)(&u2) = ((t2 & (0x03)) << 6) | t3;
            *((unsigned char *)(&u2) + 1) = (t1 << 4) | (t2 >> 2);
        }

        ret = pinyin_charcmp(u1, u2);
        if (0 != ret)
            break;
        ++ps1;
        ++ps2;
    }

    return ret;
}

int binCollFuncUtf8(void *padFlag, int nKey1, const void *pKey1, int nKey2, const void *pKey2)
{
    return pinyin_strncmp_utf8(pKey1, pKey2);
}

int pinyin_strcmp(const unsigned short *str1, const unsigned short *str2)
{
    return pinyin_strncmp(str1, str2, -1);
}

int pinyin_charcasecmp(unsigned short wch1, unsigned short wch2)
{
    return CMP_CASE_CHAR(wch1, wch2);
}

int pinyin_strncasecmp(const unsigned short *str1, const unsigned short *str2, unsigned long length)
{
    unsigned long i = 0;

    if(str1 == NULL)
    {
        return -1;
    }

    if(str2 == NULL)
    {
        return 1;
    }

    for(i = 0; i < length; i++)
    {
        if(!str1[i] || !str2[i] || str1[i] != str2[i])
        {
            break;
        }
    }

    return pinyin_charcasecmp(str1[i], str2[i]);
}

int pinyin_strcasecmp(const unsigned short *str1, const unsigned short *str2)
{
    return pinyin_strncasecmp(str1, str2, -1);
}
